home *** CD-ROM | disk | FTP | other *** search
/ TOS Silver 2000 / TOS Silver 2000.iso / programm / MM2_DEV / S / DEMO / SYSLIBDE.M < prev    next >
Encoding:
Text File  |  1990-05-27  |  16.0 KB  |  432 lines

  1.  
  2. (*
  3.  *      Modul-Skelett zur Verwaltung von System-Ressourcen
  4.  *      --------------------------------------------------
  5.  *                 mit Hilfe von 'ResHandler'
  6.  *                 --------------------------
  7.  *
  8.  * Das folgende Modul 'SysLibSkeleton' ist eine beispielhafte Implementation
  9.  * für das Verwalten von Zugriffen, die eröffnet und wieder geschlossen
  10.  * werden können. Die Module 'Files', 'Excepts' oder 'TextWindows' sind
  11.  * diesbezüglich ähnlich aufgebaut.
  12.  *
  13.  * Problemstellung:
  14.  *   Beim Dateizugriff oder beim Verwenden mehrerer Fenster wird im
  15.  * Allgemeinen ein Zugriff mit einer 'Open'-Funktion erlangt und am
  16.  * Ende mit der entsprechenden 'Close'-Funktion wieder beendet.
  17.  * Für dieses Verfahren gibt viele weitere Anwendungen, z.B. für
  18.  * Module, die Stapel (Stacks), Schlangen (Queues) oder Verwenden
  19.  * von Systemvektoren, wie Timer, VBL-Queue, usw., vorsehen.
  20.  *
  21.  *   Im Allgemeinen ist es dabei wünschenswert, dem Anwenderprogramm
  22.  * die Arbeit abzunehmen, beim Programmende alle eröffneten Zugriffe
  23.  * wieder zu schließen. In der Regel sollte dies zwar am Ende des
  24.  * Programms geschehen aber bei einem Laufzeitfehler oder einfach
  25.  * schlampiger Programmierung sollte das betreffende Modul dies zur
  26.  * Not selbst erledigen können.
  27.  *
  28.  *   Man kann sich nun aber, vor Allem beim Megamax-System, Anwendungen
  29.  * vorstellen, bei denen bei Programmende die Zugriffe erhalten bleiben
  30.  * sollen, so z.B., wenn der Zugriff vom darunter liegenden Prozeß
  31.  * weitergeführt werden soll oder wenn das Programm resident bleiben
  32.  * will und weiterhin die Zugriffe benötigt.
  33.  *
  34.  *   In den betroffenen MOS-Modulen sind deshalb, wie auch im Handbuch
  35.  * in Kapitel 5.1, unter 'Allg. Hinweise zu den Modulen' vermerkt,
  36.  * 'Sys'-Funktionen vorgesehen. Diese Funktionen dienen dazu, den Zugriff
  37.  * so zu eröffnen, daß er nicht mehr automatisch geschlossen wird.
  38.  * In dem Fall ist dann das Anwenderprogramm wieder ganz und gar selbst
  39.  * für das Schließen verantwortlich.
  40.  *
  41.  *   Die folgende Modulimplementation sieht nun alle Funktionen vor, um
  42.  * sowohl das normale, automatische Schließen als auch die Sys-Funktion
  43.  * korrekt durchzuführen. Das Definitionsmodul muß dazu immer zwei
  44.  * 'Open'-Funktionen (wovon die eine mit 'Sys' beginnt) und eine Close-
  45.  * Funktion enthalten. Weiterhin sind eigene Funktionen zum Zugriff auf
  46.  * die 'Resourcen' implementierbar. Die Namensgebung ist selbstver-
  47.  * ständlich beliebig, nur sollte die Sys-Funktion auf jeden Fall mit
  48.  * diesem Prefix ("Sys") beginnen.
  49.  *
  50.  *   Außerdem ist schon alles vorgesehen, wiederholte, verschiedene
  51.  * Zugriffe zu verwalten, indem für jeden Zugriff ein Record angelegt
  52.  * wird, in dem die spezifischen Daten stehen und alle solche Records
  53.  * in einer Liste verkettet werden. Es ist unumgänglich, die Zugriffe
  54.  * untereinander zu verketten, aber sie können natürlich auch anders
  55.  * als mit einer Liste realisiert werden.
  56.  *
  57.  *   Die Verwaltung geöffneter Zugriffe in Listen und das automatische
  58.  * Schließen wird mit Hilfe des Moduls 'ResHandler' realisiert.
  59.  *
  60.  *   Das Beispielmodul zeigt eine einfache Anwendung, bei der beim
  61.  * Öffnen eines Zugriffs eine Zahl bestimmt werden kann. Mit der
  62.  * Zugriffsfunktion 'DoIt' kann dann eine Textzeile ausgegeben werden,
  63.  * die um soviel Zeichen eingerückt ist, wie vorher beim Öffnen bestimmt
  64.  * wurde. Für dies einfache Beispiel findet sich ganz am Ende ein Modul,
  65.  * das die Verwendung dieses Systemmoduls demonstiert. Diese gesamte
  66.  * Textdatei kann auf einmal vom Compiler übersetzt werden und dann das
  67.  * enthaltene Testmodul mit Ctrl-A von der Shell aus gestartet werden.
  68.  *
  69.  *   Um eigene Systemmodule zu erstellen, sind die Namen im Definitions-
  70.  * text und ggf. die Parameter bei den Open-Funktionen zu ändern und
  71.  * eigene Zugriffsroutinen zu deklarieren. Im Implementationsteil müssen
  72.  * die Zugriffsroutinen neu programmiert werden (anhand der Beispielrou-
  73.  * tine 'DoIt') und in den Funktionen 'myOpen' und 'myClose' müssen ggf.
  74.  * die externen Zugriffe initialisiert bzw. rückgesetzt werden. Außerdem
  75.  * muß das Zugriffs-Record 'MyType' mit den benötigten Datenfeldern
  76.  * versehen werden.
  77.  *
  78.  *   Alle weiteren Änderungsstellen sind im Text mit drei Punkten im
  79.  * Kommentar versehen. Die Kontrollausgaben sollten natürlich auch
  80.  * entfernt werden.
  81.  *)
  82.  
  83.  
  84. DEFINITION MODULE SysLibSkeleton;
  85.  
  86. TYPE  Handle;
  87.  
  88. PROCEDURE OpenIt (VAR hdl: Handle; param: CARDINAL; VAR ok: BOOLEAN);
  89.   (*
  90.    * Öffnet einen Zugriff (Ressource).
  91.    * 'param' bestimmt dabei die Einrückungsweite (s. 'DoIt').
  92.    * Bei Prozeßende wird der Zugriff automatisch geschlossen
  93.    *)
  94.  
  95. PROCEDURE SysOpenIt (VAR hdl: Handle; param: CARDINAL; VAR ok: BOOLEAN);
  96.   (*
  97.    * Wie 'OpenIt', jedoch als 'Sys'-Funktion (siehe Handbuch, Kap. 5.1)
  98.    * Bei Prozeßende wird der Zugriff NICHT automatisch geschlossen, sondern
  99.    * muß manuell vom anwendenden Programm geschlossen werden!
  100.    *)
  101.  
  102. PROCEDURE DoIt (hdl: Handle; data: ARRAY OF CHAR; VAR ok: BOOLEAN);
  103.   (*
  104.    * Gibt Textzeile aus, eingerückt um den Wert, der beim Öffnen des
  105.    * Zugriffs f. 'hdl' angegeben wurde.
  106.    *)
  107.  
  108. PROCEDURE CloseIt (VAR hdl: Handle);
  109.   (*
  110.    * Beendet Zugriff auf 'hdl'
  111.    *)
  112.  
  113. END SysLibSkeleton.
  114.  
  115. (* ----------------------------------------------------------------------- *)
  116.  
  117. IMPLEMENTATION MODULE SysLibSkeleton;
  118.  
  119. (*$Y+  Kennzeichnung für Systemmodule mit "shared data" (s. Handbuch) *)
  120.  
  121. FROM SYSTEM IMPORT ADDRESS, ADR;
  122. FROM Storage IMPORT SysAlloc, DEALLOCATE;
  123. FROM ErrBase IMPORT RtnCond, ErrResp, RaiseError;
  124. FROM MOSGlobals IMPORT OutOfMemory;
  125. FROM ResHandler IMPORT Resource, CreateResource,
  126.                        InsertHandle, InsertSysHandle,
  127.                        RemoveHandle, HandleInList;
  128.  
  129. (* ... werden ggf. nicht benötigt: *)
  130.   IMPORT TOSIO, InOut, Strings;
  131.  
  132.  
  133. TYPE MyType = RECORD
  134.                 (* ... hier folgen die eigenen Datenfelder: *)
  135.                   col: CARDINAL;
  136.               END;
  137.  
  138. TYPE Handle = POINTER TO MyType;      (* Der Opaque Typ wird redeklariert *)
  139.  
  140. VAR HandleList: Resource;             (* Liste zum Verketten der Zugriffe *)
  141.  
  142.  
  143. PROCEDURE myClose (hdlAddr: ADDRESS; user: BOOLEAN);
  144.   (*
  145.    * Diese Prozedur übernimmt das Schließen eines Zugriffs und wird
  146.    * bei '(Sys)InsertHandle' als Parameter für die Freigabeprozedur
  147.    * übergeben.
  148.    *)
  149.   VAR hdl: Handle;
  150.   BEGIN
  151.     hdl:= hdlAddr; (* Initialisierung (Typkonvertierung) *)
  152.     WITH hdl^ DO
  153.       (* ... hier müssen ggf. Rücksetzungen erfolgen, wie *)
  154.       (*     z.B. veränderte Vektoren wiederherzustellen. *)
  155.       IF user THEN
  156.         InOut.WriteString( 'Der Benutzer ');
  157.       ELSE
  158.         InOut.WriteString( 'Das System ');
  159.       END;
  160.       InOut.WriteString ('schließt den Zugriff auf Spalte ');
  161.       InOut.WriteCard (col, 0);
  162.       InOut.WriteLn;
  163.     END;
  164.     DEALLOCATE (hdl, 0)     (* Speicher f. Record freigeben *)
  165.   END myClose;
  166.  
  167. PROCEDURE myOpen ( VAR hdl     : Handle;
  168.                        param   : CARDINAL;
  169.                    VAR ok      : BOOLEAN;
  170.                        sysLevel: BOOLEAN);
  171.   (*
  172.    * Ist sysLevel 'TRUE', dann wird der Zugriff bei Prozessende nicht
  173.    * automatisch geschlossen.
  174.    *)
  175.   VAR strOk, found, error: BOOLEAN;
  176.   BEGIN
  177.     ok:= FALSE;
  178.     (* Nur neu öffnen, wenn Zugriff noch nicht geöffnet ist: *)
  179.     IF NOT HandleInList (HandleList, hdl) THEN
  180.       (*
  181.        * Nun Speicher für Record anfordern. Dazu wird eine 'Sys'-Funktion
  182.        * benutzt (wichtig!!), damit dieser auch 'InsertSysHandle' überlebt.
  183.        * Auch, wenn andere Ressourcen (GEM, Vektoren, Prozesse, usw.) hier
  184.        * angelegt werden, sollten möglichst immer 'Sys'-Funktion dazu ver-
  185.        * wendet werden. Ist dies nicht möglich, darf hier auch keine Sys-
  186.        * Funktion angeboten werden, damit's nicht schiefgeht!
  187.        * Natürlich kann dieses Modul auch Dinge tun, wozu überhaupt keine
  188.        * externen Ressourcen (wie der Speicher für das Record) geöffnet werden
  189.        * müssen, z.B. wenn hier nur damit ein Daten-Stack aufgebaut wird.
  190.        * Dann kann hier natürlich problemlos eine Sys-Funktion angeboten
  191.        * werden.
  192.        *)
  193.       SysAlloc (hdl, SIZE (hdl^));
  194.       IF hdl # NIL THEN
  195.         (* Record in der Resource-Liste HandleList verketten *)
  196.         IF sysLevel THEN
  197.           (* System-Zugriff; nur verwenden, wenn der Rest (Speicher, usw.)
  198.            * auch mit Sys-Funktionen angelegt wurde! *)
  199.           InsertSysHandle (HandleList, hdl, myClose, error);
  200.         ELSE
  201.           (* normaler Zugriff *)
  202.           InsertHandle (HandleList, hdl, myClose, error);
  203.         END;
  204.         IF error THEN
  205.           DEALLOCATE (hdl, 0)
  206.         ELSE
  207.           WITH hdl^ DO
  208.             (* ... hier folgen eigene Initialisierungen *)
  209.             (* ... und Zuweisungen der Record-Felder:   *)
  210.               col:= param;
  211.           END;
  212.           ok:= TRUE
  213.         END
  214.       END
  215.     END
  216.   END myOpen;
  217.  
  218. PROCEDURE OpenIt (VAR hdl: Handle; param: CARDINAL; VAR ok: BOOLEAN);
  219.   (*
  220.    * Normales Eröffnen eines Zugriffs (einer Ressource).
  221.    *)
  222.   BEGIN
  223.     myOpen (hdl, param, ok, FALSE)
  224.   END OpenIt;
  225.  
  226. PROCEDURE SysOpenIt (VAR hdl: Handle; param: CARDINAL; VAR ok: BOOLEAN);
  227.   (*
  228.    * Dauerhaftes Eröffnen eines Zugriffs (einer Ressource).
  229.    *)
  230.   BEGIN
  231.     myOpen (hdl, param, ok, TRUE)
  232.   END SysOpenIt;
  233.  
  234.  
  235. PROCEDURE DoIt (hdl: Handle; data: ARRAY OF CHAR; VAR ok: BOOLEAN);
  236.   (*
  237.    * Operation auf dem Zugriff (auf der Ressource)
  238.    *)
  239.   BEGIN
  240.     (* Existiert Zugriff überhaupt ? *)
  241.     IF HandleInList (HandleList, hdl) THEN
  242.       WITH hdl^ DO                   (* ja, dann ist der 'handle' gültig. *)
  243.         (* ...hier wird ein Zugriff durchgeführt: *)
  244.         InOut.WriteString (Strings.Space (col));  (* 'col' aus Record *)
  245.         InOut.WriteString (data);
  246.         InOut.WriteLn;
  247.       END
  248.     END
  249.   END DoIt;
  250.  
  251.  
  252. PROCEDURE CloseIt (VAR hdl: Handle);
  253.   BEGIN
  254.     (*
  255.      * Falls der angegebene Zugriff noch existiert, wird der
  256.      * belegte Speicher freigegeben und der Zugriff aus der Liste
  257.      * 'HandleList' gelöscht.
  258.      *)
  259.     RemoveHandle (HandleList, hdl)
  260.   END CloseIt;
  261.  
  262.  
  263. VAR error: BOOLEAN;
  264.  
  265. BEGIN
  266.   CreateResource (HandleList, error);
  267.   IF error THEN
  268.     RaiseError (OutOfMemory, '', selfCaused, mustAbort)
  269.   END;
  270. END SysLibSkeleton.
  271.  
  272. (* ----------------------------------------------------------------------- *)
  273.  
  274. MODULE SysLibDemo;
  275.  
  276. (*
  277.  * Dies Modul demonstiert die Anwendung des obigen Beispielmoduls.
  278.  *
  279.  * Es öffnet erst zwei Zugriffe, dann wendet es die Zugriffsfunktionen an,
  280.  * dann startet es einen Tochterprozeß, welcher ebenfalls zwei Zugriffe
  281.  * eröffnet. Einer der Zugriffe wird mit der Sys-Funktion geöffnet. Der
  282.  * Prozeß gibt auch mit 'DoIt' Text aus und endet dann, ohne die Zugriffe
  283.  * zu schließen. Der eine Zugriff wird sodann vom Systemmodul geschlossen,
  284.  * während der Sys-Zugriff erhalten bleibt. Dann werden im ersten Prozeß
  285.  * wieder Ausgaben mit 'DoIt' gemacht, wobei auch der noch vorhandene
  286.  * Sys-Zugriff benutzt wird. Am Ende wird dann einer der beiden ersten
  287.  * Zugriffe ordnungsgemäß geschlossen, sodaß das Systemmodul den anderen
  288.  * wiederum automatisch schließt.
  289.  *
  290.  * Der Sys-Zugriff muß (immer) explizit geschlossen werden, was in der
  291.  * 'Termination'-Funktion geschieht, die zuvor mit 'CatchProcessTerm'
  292.  * einen Aufruf bei Prozeßende angefordert hat. Dies ist besser, als am
  293.  * Ende des Programmtextes diesen Aufruf durchzuführen, weil bei einem
  294.  * Laufzeitfehler diese Programmstelle nicht mehr erreicht werden würde
  295.  * und der Zugriff für immer (bis zum Reset des Rechners) als "Leiche"
  296.  * im Speicher verleiben würde.
  297.  *
  298.  * Die Fehlerabfragen ('ok') wurden absichtlich weggelassen, da hier sowieso
  299.  * alles funktionieren sollte (Speicher sollte ausreichen).
  300.  *)
  301.  
  302. IMPORT GEMDOSIO; (*$E MOS ..machen wir ein TOS-Programm draus. *)
  303.  
  304. FROM SYSTEM IMPORT ADR;
  305. FROM SysLibSkeleton IMPORT Handle, OpenIt, SysOpenIt, DoIt, CloseIt;
  306. FROM MOSGlobals IMPORT MemArea;
  307. FROM ModCtrl IMPORT CallProcess;
  308. FROM ResCtrl IMPORT CatchRemoval, RemovalCarrier;
  309. FROM PrgCtrl IMPORT CatchProcessTerm, TermCarrier;
  310. IMPORT InOut;
  311.  
  312. MODULE local;
  313.  
  314.   (*
  315.    * Dies lokale Modul enthält eine Prozedur, die als neuer Prozeß unter
  316.    * dem Hauptprogramm gestartet wird.
  317.    * Ebenso könnte zur Demonstration mit 'Loader.CallModule' ein anderes
  318.    * Modul als Tochterprozeß gestartet werden, das dann 'SysLibSkeleton'
  319.    * importiert und die im Folgenden gezeigten Funktionen aufruft.
  320.    *)
  321.  
  322.   IMPORT Handle, OpenIt, SysOpenIt, DoIt, CloseIt;
  323.   IMPORT InOut;
  324.  
  325.   EXPORT otherProgram, sysHdl;
  326.  
  327.   VAR sysHdl: Handle;
  328.  
  329.   PROCEDURE otherProgram;
  330.     VAR ok: BOOLEAN;
  331.         hdl: Handle;
  332.     BEGIN
  333.       (* Normalen Zugriff zu diesem Prozeß öffnen *)
  334.       OpenIt (hdl, 12, ok);
  335.         InOut.WriteString ('Öffne Zugriff auf Spalte 12');
  336.         InOut.WriteLn;
  337.  
  338.       (* Dauerhaften Zugriff öffnen *)
  339.       SysOpenIt (sysHdl, 14, ok);
  340.         InOut.WriteString ('Öffne Sys-Zugriff 2 auf Spalte 14');
  341.         InOut.WriteLn;
  342.  
  343.       DoIt (hdl,    'Dies ist 2. Prozeß, normaler Zugriff', ok);
  344.       DoIt (sysHdl, 'Dies ist 2. Prozeß, Sys-Zugriff', ok)
  345.  
  346.       (* Der Sys-Zugriff soll nicht geschlossen werden, da im *)
  347.       (* Vaterprozeß noch darauf zugegriffen werden wird..    *)
  348.       (* Der andere Prozeß wird einfach vergessen - er wird   *)
  349.       (* vom Systemmodul geschlossen werden.                  *)
  350.     END otherProgram;
  351.  
  352.   END local;
  353.  
  354. PROCEDURE Removal;
  355.   VAR wait: CHAR;
  356.   BEGIN
  357.     InOut.WriteLn;
  358.     InOut.WriteString ('Taste...');
  359.     InOut.Read (wait);
  360.   END Removal;
  361.  
  362. PROCEDURE Termination;
  363.   VAR wait: CHAR;
  364.   BEGIN
  365.     (* Der Sys-Zugriff muß spätestens hier geschlossen werden, sonst bleibt
  366.      * er für immer geöffnet (und belegt damit unnötig Speicher). *)
  367.     InOut.WriteString ('Schließe manuell Sys-Zugriff auf Spalte 14:');
  368.     InOut.WriteLn;
  369.     CloseIt (sysHdl);
  370.     InOut.WriteLn;
  371.     (* ... hier könnten eigene Ressourcen geschlossen werden. *)
  372.   END Termination;
  373.  
  374. VAR ok: BOOLEAN;
  375.     exitCode: INTEGER;                  (* Exit-Code von 2. Prozeß *)
  376.     stack: ARRAY [1..4096] OF CARDINAL; (* Stack für 2. Prozeß: 8 KB *)
  377.     wsp: MemArea;
  378.     rCarrier: RemovalCarrier;
  379.     tCarrier: TermCarrier;
  380.  
  381.     hdl: ARRAY [1..2] OF Handle;        (* 'Handles' für zwei Zugriffe *)
  382.  
  383. BEGIN
  384.   (* Bei Programmende soll 'Removal' aufgerufen werden, um auf einen
  385.    * Tastendruck zu warten: *)
  386.   wsp.bottom:= NIL; (* Damit wird der Stack des Hauptprozesses benutzt *)
  387.   CatchRemoval (rCarrier, Removal, wsp);
  388.  
  389.   (* Bei Prozeßende soll 'Termination' aufgerufen werden *)
  390.   wsp.bottom:= NIL;  (* Damit wird der Stack des Hauptprozesses benutzt *)
  391.   CatchProcessTerm ( tCarrier, Termination, wsp );
  392.     (* Hier hätte auch 'CatchRemoval' verwendet werden  *)
  393.     (* können, da dies beim Hauptmodul, sofern es nicht *)
  394.     (* resident ist, keinen Unterschied macht.          *)
  395.  
  396.   (* Ersten Zugriff öffnen *)
  397.   OpenIt (hdl [1], 2, ok);
  398.     InOut.WriteString ('Öffne Zugriff 1 auf Spalte 2');
  399.     InOut.WriteLn;
  400.   (* Zweiten Zugriff öffnen *)
  401.   OpenIt (hdl [2], 4, ok);
  402.     InOut.WriteString ('Öffne Zugriff 2 auf Spalte 4');
  403.     InOut.WriteLn;
  404.  
  405.   (* Funktionen auf die beiden Zugriffe durchführen *)
  406.   DoIt (hdl [1], 'Dies ist 1. Prozeß, Zugriff 1', ok);
  407.   DoIt (hdl [2], 'Dies ist 1. Prozeß, Zugriff 2', ok);
  408.  
  409.   (* Tochterprozeß starten *)
  410.   InOut.WriteLn;
  411.   wsp.bottom:= ADR (stack);
  412.   wsp.length:= SIZE (stack);
  413.   CallProcess (otherProgram, wsp, ok, exitCode);
  414.   InOut.WriteLn;
  415.  
  416.   (* Funktionen auf die beiden Zugriffe dieses Prozesses und des    *)
  417.   (* residenten, vom Tochterprozeß geöffneten, Zugriffs durchführen *)
  418.   DoIt (hdl [2], 'Dies ist wieder 1. Prozeß, Zugriff 2', ok);
  419.   DoIt (hdl [1], 'Dies ist wieder 1. Prozeß, Zugriff 1', ok);
  420.   DoIt (sysHdl,  'Dies ist der Sys-Zugriff', ok);
  421.  
  422.   (* Einen der hier geöffneten Zugriffe selber schließen,  *)
  423.   (* der andere wird testweise vom Systemmodul geschlossen *)
  424.   InOut.WriteLn;
  425.   InOut.WriteString ('Schließe manuell Zugriff 2 auf Spalte 4:');
  426.   InOut.WriteLn;
  427.   CloseIt (hdl [2]);
  428.  
  429.   InOut.WriteLn
  430.  
  431. END SysLibDemo.
  432.